import { _decorator, Node, Vec2, Vec3, Rect, v2, instantiate, sys, builtinResMgr, Material, UIRenderer, tween, v3, UITransform } from 'cc';
import { SS_Settings } from '../Data/SS_Settings';

const { ccclass, property } = _decorator;

@ccclass('CommonFunction')
export default class CommonFunction {
    //    // 深拷贝
    static DeepCopy(obj) {
        // 只拷贝对象
        if (typeof obj !== "object") return;
        // 根据obj的类型判断是新建一个数组还是一个对象
        let newObj = obj instanceof Array ? [] : {};
        for (let key in obj) {
            // 遍历obj,并且判断是obj的属性才拷贝
            if (obj.hasOwnProperty(key)) {
                // 判断属性值的类型，如果是对象递归调用深拷贝
                newObj[key] = typeof obj[key] === "object" ? CommonFunction.DeepCopy(obj[key]) : obj[key];
            }
        }
        return newObj;
    }

    // Clone对象
    static Clone(obj): any {
        let ret = { ...obj };
        return ret;
    }



    //    // 销毁子物体
    static DestroyAllChildren(parent: Node) {
        for (let i = 0; i <= parent.children.length - 1; i++) {
            let child: Node = parent.children[i];
            child.destroy();
        }
    }

    //    // 设置所有子物体可见或者不可见
    static SetAllChildrenAtive(parent: Node, active: boolean) {
        for (let i = 0; i <= parent.children.length - 1; i++) {
            let child: Node = parent.children[i];
            child.active = active;
        }
    }

    static GetFreeChild(parent: Node): Node {
        let c: Node = null;
        for (let i = 0; i <= parent.children.length - 1; i++) {
            let child = parent.children[i];
            if (child.active == false) {
                c = child;
                break;
            }
        }

        if (c == null) {
            let node: Node = instantiate(parent.children[0]);
            node.parent = parent;
            node.setPosition(0, 0);
            c = node;
        }

        return c;
    }
    static SetNodeFirstSiblingIndex(_node: Node) {
        // _node.setSiblingIndex(0);
    }
    static SetNodeLastSiblingIndex(_node: Node) {
        // _node.setSiblingIndex(_node.parent.children.length - 1);
    }

    //    // 有#的情况
    static GetQueryStringhash(key) {
        // let after = window.location.search;
        // if (after.indexOf("?") === -1) return null; // 如果url中没有传参直接返回空
        //        // key存在先通过search取值如果取不到就通过hash来取
        // after = after.substr(1) || window.location.hash.split("?")[1];
        // if (after) {
        // let reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
        // let r = after.match(reg);
        // if (r != null) {
        // return decodeURIComponent(r[2]);
        // } else {
        // return null;
        // }
        // }
    }
    //    // 没有#情况
    static GetQueryString() {
        // let data = {};
        // let src = window.location.href;
        // let index = src.indexOf("?");
        // if (index === -1) {
        // return data;
        // }
        // let dataStr = src.substring(src.indexOf("?") + 1);
        // let dataArray = dataStr.split("&");
        // dataArray.forEach((str) => {
        // let param = str.split("=");
        // data[param[0]] = param[1];
        // });
        // return data;
    }

    static NumberFormat(_param) {
        //        // let str: string[] = [`万`, `亿`, `兆`, `京`, `垓`,];
        // let value: string = "";

        // let level = 10000;
        // let sizesValue = "";
        // let isGe: boolean = false;

        //        // 判断取哪个单位
        // if (_param < Math.pow(10, 4)) {
        // level = 1;
        // sizesValue = "";
        // isGe = true;
        // } else if (_param >= Math.pow(10, 4) && _param < Math.pow(10, 8)) {
        // level = Math.pow(10, 4);
        // sizesValue = "万";
        // } else if (_param >= Math.pow(10, 8) && _param < Math.pow(10, 12)) {
        // level = Math.pow(10, 8);
        // sizesValue = "亿";
        // } else if (_param >= Math.pow(10, 12) && _param < Math.pow(10, 16)) {
        // level = Math.pow(10, 12);
        // sizesValue = "兆";
        // } else if (_param >= Math.pow(10, 16) && _param < Math.pow(10, 20)) {
        // level = Math.pow(10, 16);
        // sizesValue = "京";
        // } else if (_param >= Math.pow(10, 20)) {
        // level = Math.pow(10, 20);
        // sizesValue = "垓";
        // }

        // let num = _param / level;
        // let result: number = Math.floor(num * 100) / 100;
        // if (isGe) {
        // result = Math.floor(result);
        // }
        // value = result + sizesValue;

        // return value;
    }

    static checkIntersectOrContain(nodeA: Node, nodeB: Node) {
        const boundingBoxA = nodeA.getComponent(UITransform).getBoundingBoxToWorld();
        const boundingBoxB = nodeB.getComponent(UITransform).getBoundingBoxToWorld();
        const intersect = boundingBoxA.intersects(boundingBoxB);
        const AcontainB = boundingBoxA.containsRect(boundingBoxB);
        const BcontainA = boundingBoxB.containsRect(boundingBoxA);
        return intersect || AcontainB || BcontainA;
    }

    static checkIntersectOrContainByBoundingBox(boundingBoxA: Rect, boundingBoxB: Rect) {
        const intersect = boundingBoxA.intersects(boundingBoxB);
        const AcontainB = boundingBoxA.containsRect(boundingBoxB);
        const BcontainA = boundingBoxB.containsRect(boundingBoxA);
        return intersect || AcontainB || BcontainA;
    }

    static saveJSON(data, filename) {
        // if (!data) {
        // alert('data is null');
        // return;
        // }
        // if (!filename) {
        // filename = 'json.json'
        // }
        // if (typeof data === 'object') {
        // data = JSON.stringify(data, undefined, 4)
        // }
        //        // 文件保存
        // let blob = new Blob([data], { type: 'text/json' });
        // let e = document.createEvent('MouseEvents');
        // let a = document.createElement('a');
        // a.download = filename;
        // a.href = window.URL.createObjectURL(blob);
        // a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
        // e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        // a.dispatchEvent(e);
    }

    //    /** 使手机短时间震动 */
    static vibrateShort() {
        if (SS_Settings.curVibrate === 1) {
            // console.log("震动~~~");
            const isKSGame = typeof window['KSGameGlobal'] != 'undefined';
            if (sys.platform == sys.Platform.BYTEDANCE_MINI_GAME) {
                //@ts-ignore
                tt?.vibrateShort();
            }
            else if (isKSGame) {
                //@ts-ignore
                ks.vibrateShort()
            }
        }
    }
    //    /** 使手机长时间震动 */
    static vibrateLong() {
        if (SS_Settings.curVibrate === 1) {
            const isKSGame = typeof window['KSGameGlobal'] != 'undefined';
            if (sys.platform == sys.Platform.BYTEDANCE_MINI_GAME) {
                tt?.vibrateLong();
            }
            else if (isKSGame) {
                ks.vibrateLong()
            }
        }
    }

    /**
     * 节点置灰
     */
    static SetGray(node: Node, isGray: boolean): void {
        if (node == null || node.isValid == false) {
            return;
        }

        let material: Material = builtinResMgr.get(isGray ? "ui-sprite-gray-material" : "");
        let renders = node.getComponentsInChildren(UIRenderer);
        for (let i = 0; i < renders.length; i++) {
            renders[i].customMaterial = material;
        }
    }

    // 1阶贝塞尔(直线)
    public static bezierTo1(v1: Vec3, v2: Vec3, t: number) {
        let tempV3 = new Vec3();
        Vec3.lerp(tempV3, v1, v2, t);
        return tempV3;
    }
    // 2阶贝塞尔(曲线)
    public static bezierTo2(v1: Vec3, v2: Vec3, v3: Vec3, t: number) {
        let temp1 = this.bezierTo1(v1, v2, t);
        let temp2 = this.bezierTo1(v2, v3, t);
        return this.bezierTo1(temp1, temp2, t);
    }

    /**
     *  二阶贝塞尔曲线 运动
     * @param target
     * @param {number} duration
     * @param {} c1 起点坐标
     * @param {} c2 控制点
     * @param {Vec3} to 终点坐标
     * @param opts
     * @returns {any}
     */
    public static bezierTo(target: any, duration: number, c1: Vec3, c2: Vec3, to: Vec3, opts: any) {
        opts = opts || Object.create(null);
        /**
         * @desc 二阶贝塞尔
         * @param {number} t 当前百分比
         * @param {} p1 起点坐标
         * @param {} cp 控制点
         * @param {} p2 终点坐标
         * @returns {any}
         */
        // let twoBezier = (t: number, p1: Vec2, cp: Vec2, p2: Vec3) => {
        //     let x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;
        //     let y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;
        //     return v3(x, y, 0);
        // };
        opts.onUpdate = (arg: Vec3, ratio: number) => {
            // target.position = twoBezier(ratio, c1, c2, to);
            target.position = CommonFunction.bezierTo2(c1, c2, to, ratio);
        };
        return tween(target).to(duration, {}, opts);
    }

    // 交换数组元素
    static Swap(arr, i, j) {
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }

    // 按值拆成多个数组
    static GroupByValue(arr) {
        return arr.reduce((acc, curr) => {
            // 查找当前元素在 accumulater 中的子数组
            const group = acc.find(item => item[0].id === curr.id);
            if (group) {
                // 如果找到相同的值，则将当前元素推入相应的子数组
                group.push(curr);
            } else {
                // 否则创建新子数组
                acc.push([curr]);
            }
            return acc;
        }, []);
    }

    /**
     * 坐标转换
     */
    static convertToNodeSpaceAR(node, pos: Vec2): Vec3 {
        let out = new Vec3();
        node.getComponent(UITransform)?.convertToNodeSpaceAR(new Vec3(pos.x, pos.y, 0), out);
        return out;
    }
}

export const ArrayUtils = {
    Count<T>(array: Array<T>, check: (a: T) => boolean): number {
        let n = 0;
        for (const iterator of array) {
            if (check(iterator)) n++;
        }
        return n;
    },
    Remove<T>(array: Array<T>, element: T): boolean {
        const index = array.indexOf(element);
        if (index >= 0) {
            array.splice(index, 1);
            return true;
        }
        return false;
    },
    ToMap<T>(array: Array<T>, getkey: (arg: T) => string, out?: { [key: string]: T }): { [key: string]: T } {
        const _out: { [key: string]: T } = out || {};
        array.forEach((it) => (_out[getkey(it)] = it));
        return _out;
    },
    Flat<T, U>(array: Array<T>, action: (arg: T) => U): Array<U> {
        const newArr = [];
        array.forEach((it) => newArr.push(action(it)));
        return newArr;
    },
    FindFirst<T>(array: Array<T>, action: (arg: T) => boolean): T {
        for (let i = 0; i < array.length; i++) {
            const element = array[i];
            if (action(element)) return element;
        }
        return null;
    },
    FindLast<T>(array: Array<T>, action: (arg: T) => boolean): T {
        for (let i = array.length - 1; i >= 0; i--) {
            const element = array[i];
            if (action(element)) return element;
        }
        return null;
    },
    Shuffle(array: Array<any>) {
        let index = -1;
        let length = array.length;
        let lastIndex = length - 1;
        let size = length;
        while (++index < size) {
            const rand = index + Math.floor(Math.random() * (lastIndex - index + 1));
            const value = array[rand];
            array[rand] = array[index];
            array[index] = value;
        }
    },
    ShuffleArray(array: Array<any>) {
        array.sort(() => Math.random() - 0.5);
    },
};

// /** 调试 */
window["CommonFunction"] = CommonFunction;